home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2004 #6 / Amiga Plus CD - 2004 - No. 06.iso / AmiSoft / Comm / misc / trsi-ftpd01.lha / FAME-FTPd / source / support.c < prev    next >
C/C++ Source or Header  |  2004-04-24  |  17KB  |  565 lines

  1. /**************************************************************************************************
  2.  *  PROJECT: FAME-FTPd
  3.  *     FILE: support.c
  4.  *  PURPOSE: General support functions used frequently
  5.  *  CREATED: 05-MAY-2003
  6.  * MODIFIED: 25-JAN-2004
  7.  *   AUTHOR: Sascha 'SieGeL' Pfalz
  8.  **************************************************************************************************
  9.  * The following functions are defined here:
  10.  *
  11.  * DebugLog()                        - General debug logging
  12.  * tcp_error()          - TCP error strings
  13.  * FormatDateHookFunc()    - Hook to Formate Datestamps
  14.  * FormatStamp()        - Creates Datestring
  15.  * readline()           - Reads a line from a socket
  16.  * recvchar()                        - Recieves a char from a socket
  17.  * usputc()                            - Puts a char on a socket
  18.  * usprintf()                        - Formatted printf() on a socket
  19.  * CutCRLF()                        - Cuts CRLF from a string
  20.  * ConvertSpaces()            - Converts Spaces to Underscores
  21.  * GetFileSize()        - Returns size of a given filename
  22.  * DNSLookUp()                     - Performs a DNS Lookup on a given IP Address
  23.  * WeektopStats()                - Writes out stats files so that aCID-tOP can count the uploads
  24.  **************************************************************************************************/
  25.  
  26. #include <proto/exec.h>
  27. #include <proto/dos.h>
  28. #include <proto/locale.h>
  29.  
  30. #include <stdlib.h>
  31. #include <string.h>
  32. #include <stdarg.h>
  33. #include <sys/types.h>
  34. #include <sys/syslog.h>
  35. #include <sys/socket.h>
  36. #include <sys/errno.h>
  37. #include <sys/param.h>
  38. #include <sys/stat.h>
  39. #include <sys/ioctl.h>
  40. #include <sys/file.h>
  41. #include <sys/wait.h>
  42. #include <sys/errno.h>
  43.  
  44. #include <exec/exec.h>
  45. #include <exec/nodes.h>
  46. #include <exec/lists.h>
  47.  
  48. #include <utility/date.h>
  49. #include <utility/tagitem.h>
  50.  
  51. #include <dos/dosextens.h>
  52.  
  53. #include <proto/socket.h>
  54. #include <netinet/in.h>
  55. #include <amitcp/socketbasetags.h>
  56.  
  57. #include <proto/syslog.h>
  58. #include <libraries/syslog.h>
  59.  
  60. #include <proto/fame.h>
  61. #include <libraries/fame.h>
  62. #include <fame/fame.h>
  63.  
  64. #include <netdb.h>
  65. #include "struct_ex.h"
  66. #include "proto.h"
  67.  
  68. extern confh;
  69.  
  70. /**************************************************************************************************
  71.  * Prototype declarations:
  72.  **************************************************************************************************/
  73.  
  74. void         DebugLog(char *fmt, ...);
  75. STRPTR     tcp_error(int error);
  76. STRPTR     InitStack(void);
  77. STATIC     LONG __saveds __asm FormatDateHookFunc(register __a0 struct Hook *Hook,register __a1 UBYTE Char);
  78. BOOL         __regargs FormatStamp(struct DateStamp *Stamp,STRPTR DateBuffer,struct Locale *loc,BOOL listdate);
  79. int         readline(int fd, char *bufptr, size_t len);
  80. int         usputc(LONG s,char c);
  81. int         usprintf(LONG s,short stripcrlf,char *fmt,...);
  82. void         CutCRLF(char *s);
  83. void         ConvertSpaces(char *s);
  84. long        GetFileSize(char *fpath);
  85. long         GetFileSizeFH(BPTR fh);
  86. long         DNSLookUp(struct sockaddr_in *sin, STRPTR name);
  87. void    WeektopStats(void);
  88. void         WriteWTS(struct AcidStats *stats, long confid);
  89. void         FAMELog(char *fmt, ...);
  90.  
  91. /**************************************************************************************************
  92.  * FUNCTION: DebugLog()
  93.  *  PURPOSE: Append an entry to our debugging Logfile
  94.  *    INPUT: *fmt => sprintf-style format string
  95.  *            ... => Variable arg list
  96.  *   RETURN: -
  97.  **************************************************************************************************/
  98.  
  99. void DebugLog(char *fmt, ...)
  100.     {
  101.     char        datebuf[LEN_DATSTRING*2];
  102.     char        logname[256];
  103.     BPTR        fhandle;
  104.  
  105.     if(*fconfig->LogFile)
  106.         {
  107.         FAMEStrCopy(fconfig->LogFile,logname,255);
  108.     }
  109.     else
  110.         {
  111.         FAMEStrCopy("RAM:ftpd_debug.log",logname,255);
  112.     }
  113.     if(fhandle=Open(logname,MODE_READWRITE))
  114.         {
  115.         bzero(datebuf,sizeof(datebuf));
  116.         FormatStamp(NULL,datebuf,myloc,FALSE);
  117.         Seek(fhandle,0,OFFSET_END);
  118.         FPrintf(fhandle,"[%s]: ",datebuf);
  119.         if(&fmt+1) VFPrintf(fhandle, fmt, (long *)(&fmt + 1));
  120.     else FPuts(fhandle,fmt);
  121.         if(confh != -1)
  122.             {
  123.             if(&fmt+1) VFPrintf(confh,fmt,(long *)(&fmt +1));
  124.          else FPuts(confh,fmt);
  125.             FPuts(confh,"\n");
  126.             }
  127.         if(SysLogBase)
  128.             {
  129.             if(&fmt+1)    Log(LOG_FTP|LOG_INFO, LOG_PID, "FAME-FTPd",fmt,(LONG *)(&fmt+1));
  130.             else     Log(LOG_FTP|LOG_INFO, LOG_PID, "FAME-FTPd",fmt,NULL);
  131.             }
  132.         if(fmt[strlen(fmt)-1]!='\n') FPuts(fhandle,"\n");
  133.         Close(fhandle);
  134.         }
  135.     }
  136.  
  137. /**************************************************************************************************
  138.  * FUNCTION: tcp_error()
  139.  *  PURPOSE: Returns descriptive error text from TCP/IP stack
  140.  *    INPUT: error => Last error occured on TCP
  141.  *   RETURN: Descriptive error text
  142.  *     NOTE: Taken from smbfs source. Thanks Olaf!
  143.  **************************************************************************************************/
  144.  
  145. STRPTR tcp_error(int error)
  146.     {
  147.     struct TagItem tags[2];
  148.     STRPTR result;
  149.  
  150.     tags[0].ti_Tag    = SBTM_GETVAL(SBTC_ERRNOSTRPTR);
  151.     tags[0].ti_Data    = error;
  152.     tags[1].ti_Tag    = TAG_END;
  153.     SocketBaseTagList(tags);
  154.     result = (STRPTR)tags[0].ti_Data;
  155.     return(result);
  156.     }
  157.  
  158. /**************************************************************************************************
  159.  * FUNCTION: FormatDateHookFunc()
  160.  *  PURPOSE: Hook for locale.library/FormatDate()
  161.  *     NOTE: Used in FormatStamp()
  162.  **************************************************************************************************/
  163.  
  164. STATIC LONG __saveds __asm FormatDateHookFunc(register __a0 struct Hook *Hook,register __a1 UBYTE Char)
  165.     {
  166.     STRPTR String=Hook->h_Data;
  167.     *String++=Char;
  168.     Hook->h_Data=String;
  169.     return(TRUE);
  170.     }
  171.  
  172. /**************************************************************************************************
  173.  * FUNCTION: FormatStamp()
  174.  *  PURPOSE: Creates a human-readable datestring
  175.  *    INPUT: *Stamp            => Datestamp to use or NULL for current date
  176.  *           DateBuffer    => Buffer to hold the created string
  177.  *           *loc                => Pointer to struct *Locale or NULL to not use Locale settings
  178.  *           listdate        => TRUE   = Include date in string
  179.  *                      => FALLSE = Only include time informations
  180.  *   RETURN: Always return TRUE
  181.  *     NOTE: Requires FormatDateHookFunc() above!
  182.  **************************************************************************************************/
  183.  
  184. BOOL __regargs FormatStamp(struct DateStamp *Stamp,STRPTR DateBuffer,struct Locale *loc,BOOL listdate)
  185.     {
  186.     struct DateStamp __aligned Now;
  187.     struct Hook LocalHook={{NULL}, (HOOKFUNC)FormatDateHookFunc};
  188.     struct DateTime __aligned    mydtime;
  189.   char     timebuf[LEN_DATSTRING];
  190.  
  191.     if(!Stamp) DateStamp(Stamp = &Now);
  192.     if(loc)
  193.         {
  194.         if(DateBuffer)
  195.             {
  196.             LocalHook.h_Data=DateBuffer;
  197.             if(listdate==FALSE)    FormatDate(loc,"%d-%b-%Y %H:%M:%S",Stamp,&LocalHook);
  198.             else FormatDate(loc,"%b %d %H:%M",Stamp,&LocalHook);
  199.             }
  200.         }
  201.     else
  202.         {
  203.         mydtime.dat_Stamp      = *Stamp;
  204.         mydtime.dat_Format    = FORMAT_USA;
  205.     mydtime.dat_Flags        = NULL;
  206.         mydtime.dat_StrDay    = NULL;
  207.         mydtime.dat_StrDate    = DateBuffer;
  208.         mydtime.dat_StrTime    = timebuf;
  209.         if(!DateToStr(&mydtime)) return(FALSE);
  210.         FAMEStrCat(" ",DateBuffer);
  211.         FAMEStrCat(timebuf,DateBuffer);
  212.         }
  213.     return(TRUE);
  214.     }
  215.  
  216. /**************************************************************************************************
  217.  * FUNCTION: readline()
  218.  *  PURPOSE: Reads a line from a socket (used for Command parsing from control socket)
  219.  *    INPUT: fd            => Socket from where to read
  220.  *           bufptr    => Pointer to memory buffer to hold the string
  221.  *           len        => How many bytes we can read
  222.  *   RETURN: How many bytes where read, -1 in case of error
  223.  **************************************************************************************************/
  224.  
  225. int readline(int fd, char *bufptr, size_t len)
  226.     {
  227.     char *bufx = bufptr;
  228.     static char *bp;
  229.     static int cnt = 0;
  230.     char    c;
  231.  
  232.     FAMEFillMem(readtmp,0,CMDBUF_TEMP);
  233.     while(--len > 0)
  234.         {
  235.         if(--cnt <=0)
  236.             {
  237.       cnt = recv(fd,readtmp,sizeof(readtmp), 0);
  238.             if(cnt < 0)
  239.                 {
  240.         if(Errno()==EINTR)
  241.                     {
  242.                     len++;        /* The while() will decrement */
  243.                     continue;
  244.                     }
  245.                 return(-1);
  246.                 }
  247.             if(cnt == 0) return(0);
  248.             bp = readtmp;
  249.             }
  250.         c = *bp++;
  251.         *bufptr++ = c;
  252.         if( c == '\n')
  253.             {
  254.          *bufptr = '\0';
  255.             return(bufptr - bufx);
  256.             }
  257.         }
  258.     return(-1);
  259.     }
  260.  
  261. /*************************************************************************************************
  262.  * FUNCTION: usputc()
  263.  *  PURPOSE: Buffered putchar to a socket
  264.  *    INPUT: s => Socket where to write to
  265.  *           c => Character to put on socket
  266.  *   RETURN: -1 in case of Error else 0
  267.  *************************************************************************************************/
  268.  
  269. int usputc(LONG s,char c)
  270.     {
  271.     return send(s,&c,1,0);
  272.     }
  273.  
  274. /*************************************************************************************************
  275.  * FUNCTION: usprintf()
  276.  *  PURPOSE: printf() style writing on socket *
  277.  *    INPUT:    s             => Socket where to send the data
  278.  *           stripcrlf     => CRLF_STRIP will remove and add CRLF, CRLF_NOSTRIP just sends AS-IS
  279.  *           *fmt             => sprintf() style Format String
  280.  *            ...             => Variable arg list
  281.  *   RETURN: Amount of bytes sent
  282.  *************************************************************************************************/
  283.  
  284. int usprintf(long s,short stripcrlf,char *fmt, ...)
  285.     {
  286.     int len;
  287.  
  288.     FAMEFillMem(uspbuf,0,1024);
  289.     RawDoFmt(fmt, (long *)(&fmt + 1), (void (*))"\x16\xc0\x4e\x75",uspbuf);
  290.     if(stripcrlf==CRLF_STRIP)
  291.         {
  292.         CutCRLF(uspbuf);
  293.         FAMEStrCat("\r\n",uspbuf);
  294.         }
  295.     len = send(s,uspbuf,strlen(uspbuf),0);
  296.     return(len);
  297.     }
  298.  
  299. /*************************************************************************************************
  300.  * FUNCTION: CutCRLF()
  301.  *  PURPOSE: Function to cut out CRLF chars
  302.  *    INPUT: s => String where to cut the CRLF chars
  303.  *   RETURN: -
  304.  *     NOTE: Function modifies passed buffer directly!
  305.  *************************************************************************************************/
  306.  
  307. void CutCRLF(char *s)
  308.     {
  309.     char *d=s;
  310.  
  311.     while(*d)
  312.         {
  313.         if(*d=='\n' || *d=='\r') *d++;
  314.         else *s++=*d++;
  315.         }
  316.     *s='\0';
  317.     }
  318.  
  319. /*************************************************************************************************
  320.  * FUNCTION: ConvertSpaces()
  321.  *  PURPOSE: Function to convert spaces to underscores
  322.  *    INPUT: s => String where to convert the spaces
  323.  *   RETURN: -
  324.  *     NOTE: Function modifies passed buffer directly!
  325.  *************************************************************************************************/
  326.  
  327. void ConvertSpaces(char *s)
  328.     {
  329.     char *d=s;
  330.  
  331.     while(*d)
  332.         {
  333.         if(*d==' ' || *d=='/' || *d==':')
  334.             {
  335.             *s++='_';
  336.             *d++;
  337.             }
  338.         else *s++=*d++;
  339.         }
  340.     *s='\0';
  341.     }
  342.  
  343. /**************************************************************************************************
  344.  * FUNCTION: GetFileSize()
  345.  *  PURPOSE: Returns size of a given filename by Open()ing the file and passing fh to GetFileSizeFH()
  346.  *    INPUT: Name of file
  347.  *   RETURN: Size of file or -1 in case of an error
  348.  **************************************************************************************************/
  349.  
  350. long GetFileSize(char *fpath)
  351.     {
  352.     BPTR    testit;
  353.     long    fsize;
  354.  
  355.     if(testit = Open(fpath,MODE_OLDFILE))
  356.         {
  357.         fsize = GetFileSizeFH(testit);
  358.         Close(testit);
  359.         return(fsize);
  360.         }
  361.     else
  362.         {
  363.         char errbuf[120];
  364.       Fault(IoErr(),NULL,errbuf,120);
  365.       DebugLog("GetFileSize(): %s: %s",fpath,errbuf);
  366.         return(-1);
  367.         }
  368.     }
  369.  
  370. /**************************************************************************************************
  371.  * FUNCTION: GetFileSizeFH()
  372.  *  PURPOSE: Returns size of a given filehandle
  373.  *    INPUT: Opened filehandle
  374.  *   RETURN: Size of file or -1 in case of an error
  375.  **************************************************************************************************/
  376.  
  377. long GetFileSizeFH(BPTR fh)
  378.     {
  379.     FAMEFillMem(fib,0,sizeof(struct FileInfoBlock));
  380.     ExamineFH(fh,fib);
  381.     return(fib->fib_Size);
  382.     }
  383.  
  384. /**************************************************************************************************
  385.  * FUNCTION: DNSLookUp()
  386.  *  PURPOSE: Performs a DNS Lookup on a given IP Address.
  387.  *    INPUT: ip   => IP Address to check (struct sockaddr_in *)
  388.  *           name => Resolved hostname.
  389.  *   RETURN: 0 if lookup was successful, else -1 to indicate error
  390.  **************************************************************************************************/
  391.  
  392. long DNSLookUp(struct sockaddr_in *sin, STRPTR name)
  393.     {
  394.     struct     hostent *host;
  395.     int            retries = 0;
  396.  
  397.     while(retries < CONNECT_RETRY)
  398.     {
  399.         host = gethostbyaddr((char *)&sin->sin_addr,sizeof(struct in_addr),AF_INET);
  400.         if(host)
  401.             {
  402.         FAMEStrCopy(host->h_name,name,255);
  403.             return(0);
  404.         }
  405.         switch(h_errno)
  406.             {
  407.             case    TRY_AGAIN:    retries++;
  408.                                                 continue;
  409.             default:                    return(-1);   // Any other error is non-recoverable, so return
  410.  
  411.             }
  412.         }
  413.     }
  414.  
  415. /**************************************************************************************************
  416.  * FUNCTION: WeektopStats()
  417.  *  PURPOSE: Writes aCID-tOP compatible data so that uploads can be counted
  418.  *    INPUT: -
  419.  *   RETURN: -
  420.  *    NOTES: This function is called AFTER (!) the socket is closed, no user communication
  421.  *           is possible here except using EasyRequest()ers! See also main()
  422.  **************************************************************************************************/
  423.  
  424. void WeektopStats(void)
  425.     {
  426.     struct    FTPUploads *f1;
  427.     struct    AcidStats *astats;
  428.   long        lv,retries;
  429.     BOOL        needupdate = FALSE;
  430.     static    char aslock[] = "T:FTPd_as.lock";
  431.     BPTR        lockfp;
  432.  
  433.     if(!(astats = AllocPooled(mem_pool,sizeof(struct AcidStats) * (FameInfo->NodeCount+1))))
  434.         {
  435.         fail(ERROR_NO_FREE_STORE,"Cannot allocate AcidStats structure!!!");
  436.         return;
  437.         }
  438.     for(f1=(struct FTPUploads *)filelist.mlh_Head;f1!=(struct FTPUploads *)&filelist.mlh_Tail;f1=(struct FTPUploads *)f1->Node.mln_Succ)
  439.         {
  440.         astats[f1->ConfNum].UserNumber = fstats->UserNumber;
  441.         astats[f1->ConfNum].ULFiles++;
  442.     FAMEAdd64(NULL,f1->FileSize,&astats[f1->ConfNum].BytesHi);
  443.         needupdate = TRUE;
  444.     }
  445.     if(needupdate == FALSE) return;
  446.  
  447.     /* Stats exist, first create our Lockfile so we can safely update/create the stats */
  448.  
  449.     retries = lockfp = 0;
  450.     while(1)
  451.         {
  452.         if(retries > WTS_RETRY)
  453.             {
  454.             fail(NULL,"Cannot lock to write aCID-tOP stats!");
  455.             return;
  456.             }
  457.         lockfp = Lock(aslock,SHARED_LOCK);
  458.         if(lockfp)
  459.             {
  460.             UnLock(lockfp);
  461.             Delay(WTS_RETRY_DELAY);
  462.             retries++;
  463.             continue;
  464.             }
  465.         if(!(lockfp = Open(aslock,MODE_NEWFILE)))    /* File cannot be created, someone else was faster, wait */
  466.             {
  467.             Delay(WTS_RETRY_DELAY);
  468.             retries++;
  469.             continue;
  470.             }
  471.         break;
  472.         }
  473.  
  474.     /* Lockfile is created and open, write out the stats */
  475.  
  476.     for(lv = 0; lv < FameInfo->NodeCount+1; lv++)
  477.         {
  478.     if(astats[lv].UserNumber)
  479.             {
  480.             WriteWTS(&astats[lv],lv);
  481.             }
  482.         }
  483.  
  484.     /* And now remove our lockfile so that other instances can update, too */
  485.  
  486.     Forbid();
  487.     Close(lockfp);
  488.     DeleteFile(aslock);
  489.     Permit();
  490.     }
  491.  
  492. /**************************************************************************************************
  493.  * FUNCTION: WriteWTS()
  494.  *  PURPOSE: Writes a member of AcidStats after aggregation of all uploaded files
  495.  *    INPUT: stats    => Pointer to one member of struct AcidStats
  496.  *           confid => The conference id for which these stats are counted
  497.  *   RETURN: -
  498.  **************************************************************************************************/
  499.  
  500. void WriteWTS(struct AcidStats *stats, long confid)
  501.     {
  502.     static    char asname[] = "FAME:ExternEnv/Doors/FTPd-AT_%ld.dat";
  503.     BPTR        statsfp;
  504.     char        fname[128];
  505.     long        size,lv;
  506.     struct    AcidStats    *astemp;
  507.     BOOL        foundit = FALSE;
  508.  
  509.     if(!(astemp = AllocPooled(mem_pool,sizeof(struct AcidStats))))
  510.         {
  511.         DebugLog("WriteWTS(): Cannot allocate temporary filebuffer!");
  512.         return;
  513.         }
  514.   SPrintf(fname,asname,confid);
  515.   statsfp = Open(fname,MODE_READWRITE);
  516.     if(!statsfp)
  517.         {
  518.         DebugLog("WriteWTS(): Cannot open %s for writing!",fname);
  519.     FreePooled(mem_pool,astemp,sizeof(struct AcidStats));
  520.         return;
  521.         }
  522.     size = GetFileSizeFH(statsfp);
  523.     if(size)                /* Members inside our datafile, so search for the right file and seek to position: */
  524.         {
  525.         for(lv = 0; lv < (size/sizeof(struct AcidStats)); lv++)
  526.             {
  527.             Seek(statsfp,lv * sizeof(struct AcidStats),OFFSET_BEGINNING);
  528.             if(!Read(statsfp,astemp,sizeof(struct AcidStats)))
  529.                 {
  530.         Close(statsfp);
  531.             FreePooled(mem_pool,astemp,sizeof(struct AcidStats));
  532.         DebugLog("WriteWTS(): Error reading existing datafile %s!",fname);
  533.                 return;
  534.                 }
  535.             if(astemp->UserNumber == stats->UserNumber)
  536.                 {
  537.           Seek(statsfp, lv * sizeof(struct AcidStats), OFFSET_BEGINNING);
  538.                 foundit = TRUE;
  539.                 stats->ULFiles+=astemp->ULFiles;
  540.                 FAMEAdd64(astemp->BytesHi,astemp->BytesLo,&stats->BytesHi);
  541.                 break;
  542.                 }
  543.             }
  544.     if(foundit == FALSE) 
  545.             {
  546.             Seek(statsfp, 0L, OFFSET_END);
  547.             }
  548.         }
  549.     else
  550.         {
  551.     Seek(statsfp,0L,OFFSET_BEGINNING);
  552.         }
  553.     if(Write(statsfp,stats,sizeof(struct AcidStats))!=sizeof(struct AcidStats))
  554.         {
  555.     Close(statsfp);
  556.         DeleteFile(fname);
  557.     FreePooled(mem_pool,astemp,sizeof(struct AcidStats));
  558.         DebugLog("WriteWTS(): Writing to %s failed - File removed!",fname);
  559.         return;
  560.         }
  561.     Close(statsfp);
  562.   FreePooled(mem_pool,astemp,sizeof(struct AcidStats));
  563.     }
  564.  
  565.